"""
测试套件模块
"""
import os, sys, importlib
from config.config import CASE_PATH
from utils.log import Logger

class Suite:

    module_name_ = os.path.basename(__file__).split('.')[0]
    logger = Logger.get_logger(module_name_)
    # 1.给定一个包名，返回包中所有以test开始或结束的模块名称
    @classmethod
    def get_test_module_names(cls, path):
        module_names = []
        try:
            files = os.listdir(path)
            for file in files:
                filename = file.split('.')[0]
                if filename.startswith('test') or filename.endswith('test'):
                    module_names.append(filename)
        except Exception as e:
            cls.logger.error(f'路径{path}异常' + str(e))
        return module_names

    # 2.获取指定模块名下的以Test开始或者结束的类名列表
    @classmethod
    def get_test_class_names(cls, pakage_name, module_name):
        class_names = []
        try:
            module_obj = __import__(pakage_name, fromlist=[module_name])  # 通过反射获得模块对象
            import inspect
            # 获取模块对象下的类
            class_list = inspect.getmembers(module_obj, inspect.isclass)
            for c in class_list:
                class_name = c[0]
                if class_name.startswith('Test') or class_name.endswith('Test'):
                    class_names.append(class_name)
        except Exception as e:
            cls.logger.error(f'{pakage_name}或者{module_name}异常' + str(e))
        return class_names

    # 3.通过指定的类名获取类下的方法名列表
    @classmethod
    def get_test_method_names(cls, pakage_name, module_name, class_name):
        method_list = []
        try:
            module_obj = __import__(pakage_name, fromlist=[module_name])
            class_name = getattr(module_obj, class_name)
            method_names = dir(class_name)
            for method in method_names:
                if not method.startswith('_'):
                    if method.startswith('test') or method.endswith('test'):
                        method_list.append(method)
        except Exception as e:
            cls.logger.error(f'{pakage_name},{module_name}或{class_name}异常' + str(e))

        return method_list

    @classmethod
    def get_all_test_method_names(cls, module_path):
        """
        获取指定路径下所有符合要求的模块中的类中的方法名列表
        :param module_path:某个指定路径
        :return:方法名列表
        """
        all_method_names = []  # 所有方法名的列表
        try:
            rootpath = sys.path[1]  # 项目的根路径
            abspath = os.path.abspath(module_path)  # 指定相对路径的绝对路径
            root_package_name = abspath[(len(rootpath) + 1):].replace('\\', '.')  # 获取模块的根包名

            module_names = cls.get_test_module_names(module_path)  # 调用方法获取所有符合要求的模块名

        # base.case.test_case01
            for module_name in module_names:
                package_full_name = root_package_name + '.' + str(module_name)  # 拼接包全名
                class_names = cls.get_test_class_names(package_full_name, module_name)
                for class_name in class_names:
                    method_names = cls.get_test_method_names(package_full_name, module_name, class_name)
                    for mn in method_names:
                        all_method_names.append(mn)
        except Exception as e:
            cls.logger.error(f'{module_path}异常' + str(e))
        return all_method_names

    @classmethod
    def get_testcase_class(cls, module_path):
        """
        获取指定路径下所有符合要求的模块中的类中的方法名列表
        :param module_path:某个指定路径
        :return:方法名列表
        """
        all_class_names = []  # 所有方法名的列表
        try:
            rootpath = sys.path[1]  # 项目的根路径
            abspath = os.path.abspath(module_path)  # 指定相对路径的绝对路径
            root_package_name = abspath[(len(rootpath) + 1):].replace('\\', '.')  # 获取模块的根包名

            module_names = cls.get_test_module_names(module_path)  # 调用方法获取所有符合要求的模块名

            # base.case.test_case01
            for module_name in module_names:
                package_full_name = root_package_name + '.' + str(module_name)  # 拼接包全名
                class_names = cls.get_test_class_names(package_full_name, module_name)
                for cn in class_names:
                    all_class_names.append(cn)
        except Exception as e:
            cls.logger.error(f'{module_path}异常' + str(e))
        return all_class_names

    @classmethod
    def suite(cls):
        testcase_fun = Suite.get_all_test_method_names(CASE_PATH)
        testcase_class = Suite.get_testcase_class(CASE_PATH)
        testcase_module = Suite.get_test_module_names(CASE_PATH)
        # module = importlib.import_module('test.cases')
        class_list = []
        try:
            for tcm in testcase_module:
                module = importlib.import_module(f'test.cases.{tcm}')
                for tcc in testcase_class:
                    if hasattr(module, tcc):
                        myclass = getattr(module, tcc)
                        # class_list.append(myclass)
                        for tcf in testcase_fun:
                            if hasattr(myclass, tcf):
                                myfun = getattr(myclass(), tcf)
                                # myfun()
                                class_list.append(myfun)
        except Exception as e:
            cls.logger.error('run错误' + e.__str__())
        return class_list

class Run:

    module_name_ = os.path.basename(__file__).split('.')[0]
    logger = Logger.get_logger(module_name_)

    def __init__(self):

        pass

    @classmethod
    def run(cls,*arg):
        # print(arg)
        if arg == ():
            # class_list = cls.run()
            for fun in Suite.suite():
                # print(fun)
                fun()

    #     # else:





        pass
'''
def _isnotsuite(test):
    try:
        iter(test)
    except TypeError:
        return True
    return False


class Suite(unittest.TestSuite):
    logger = Logger().logger

    def run(self, result, debug=False):
        topLevel = False

        if getattr(result, '_testRunEntered', False) is False:
            result._testRunEntered = topLevel = True

        for index, test in enumerate(self):
            retry = getattr(test, "retry", Config.RETRY)
            if result.shouldStop:
                break

            for i in range(1, retry + 2):
                if _isnotsuite(test):
                    self._tearDownPreviousClass(test, result)
                    self._handleModuleFixture(test, result)
                    self._handleClassSetUp(test, result)
                    result._previousTestClass = test.__class__
                    if (getattr(test.__class__, '_classSetupFailed', False) or
                            getattr(result, '_moduleSetUpFailed', False)):
                        continue
                self.logger.info("用例: {}正在尝试第{}次运行!".format(test.__class__.__name__, i))
                if not debug:
                    test(result)
                else:
                    test.debug()
                if i < retry + 1:
                    # 重试判断  这段写的很丑就别细看了，欢迎优化
                    error, fail = None, None
                    fail_id = [x.get("case_id") for x in result.failures]
                    error_id = [x.get("case_id") for x in result.errors]
                    if test.case_id in fail_id:
                        fail = fail_id.index(test.case_id)
                    if test.case_id in error_id:
                        error = error_id.index(test.case_id)
                    if error is None and fail is None:
                        # 说明没有失败or错误, 停止重试
                        break
                    elif error is not None:
                        self.logger.warning("用例: {} 第{}次失败 原因: {}".format(test.__class__.__name__,
                                                                          i, str(result.errors[error]['msg'])))
                        del result.errors[error]
                    elif fail is not None:
                        self.logger.warning("用例: {} 第{}次失败 原因: {}".format(test.__class__.__name__,
                                                                          i, str(result.failures[fail]['msg'])))
                        del result.failures[fail]
                    result._previousTestClass = test.__class__
                    continue
            if self._cleanup:
                self._removeTestAtIndex(index)

        if topLevel:
            self._tearDownPreviousClass(None, result)
            self._handleModuleTearDown(result)
            result._testRunEntered = False
        return result
'''
if __name__ == '__main__':
    r = Run.run()

    pass